﻿@page "/admin/dBlogViewer"

@attribute [Authorize(Policy = Policies.IsAdmin)]
@inject HttpClient Http
@inject IMatToaster matToaster
@using BlazorBoilerplate.Shared.DataModels
@using static Microsoft.AspNetCore.Http.StatusCodes

<h1>Serilog MSSqlDb Log Viewer</h1>
<p>
    Secured Page.<br />
    Paginated viewing and fetching of system logs from the database.
</p>

@if (apiResponses == null)
{
    <LoadingBackground ShowLogoBox="true">
        <label>Loading SQL Log Data</label>
    </LoadingBackground>
}
else
{
    <div class="row" style="margin-left: 0;">
        <RefreshTimer StartEnabled="true" ElapsedEvent="@(async (_, __) => await LoadDeltaMetaAsync())" /> <MatFAB Mini="true" Class="@($"{matfab_animate_class}")" Icon="refresh" OnClick="@LoadDeltaMetaAsync" />
    </div>
    <MatTable Items="@dBLogItems" Class="mat-elevation-z5" Striped="true" PageSize="@pageSize" ShowPaging="false">
        <MatTableHeader>
            <th><div style="max-width:165px;">@*<MatSlideToggle Value="@timer.Enabled" ValueChanged="@(a=>UpdateTimer(a))" TValue="bool" Style="margin-right:16px;"></MatSlideToggle>*@ Timestamp</div></th>
            <th>Logging Level</th>
            <th>Log Message</th>
            <th>Exception (if any)</th>
            <th>Recorded Properties</th>
        </MatTableHeader>
        <MatTableRow>
            <td><span style="font-size:small">@context.TimeStamp.ToString()</span></td>
            <td><span style="font-size:small">@context.Level</span></td>
            <td><span style="font-size:small">@context.Message</span></td>
            <td><span style="font-size:small">@context.Exception?.ToString()</span></td>
            <td>
                @if (context.LogProperties?.Any() ?? false)
                    {
                    <ul>
                        @foreach (var propertyPair in context.LogProperties)
                            {
                            <li style="font-size:small">@($"{propertyPair.Key}:  {propertyPair.Value}")</li>
                            }
                    </ul>
                    }

            </td>
        </MatTableRow>
    </MatTable>
    <MatPaginator PageSize="@pageSize" Page="@(async a=> await OnPage(a))" Length="@logCountTotal" Style="background: transparent">
    </MatPaginator>
}

@code {
    ApiResponseDto[] apiResponses = new ApiResponseDto[] { };
    List<DbLog> dBLogItems = new List<DbLog>();

    private int pageSize { get; set; } = 10;
    private int pageIndex { get; set; } = 0;
    private int logCountTotal { get; set; } = 0;
    private int syncPoint { get;set;} = 0;

    string matfab_animate_class = string.Empty;
    async Task AnimateRefresh()
    {
        // this only works every other activation.....
        if (String.IsNullOrWhiteSpace(matfab_animate_class))
            matfab_animate_class = "mat-fab-animate";
        else
        {
            matfab_animate_class = String.Empty;
   
        }

    }
    protected override async Task OnInitializedAsync()
    {
        await LoadData();

    }
    async Task OnPage(MatPaginatorPageEvent e)
    {
        pageSize = e.PageSize;
        pageIndex = e.PageIndex;

        await LoadData().ConfigureAwait(true);

    }
    protected async Task LoadDeltaMetaAsync()
    {
        ApiResponseDto apiResponse = null;
        var lastEntryId = dBLogItems.Last().Id;
        try
        {
            AnimateRefresh();
            apiResponse = await Http.GetFromJsonAsync<ApiResponseDto>($"api/DbLog/delta?deltaIndex={syncPoint}");

            if (apiResponse.PaginationDetails.CollectionSizeDelta.HasValue)
            {
                if (apiResponse.PaginationDetails.CollectionSizeDelta.Value == 0)
                {
                    //Console.WriteLine($"Delta Meta refresh: no items");
                    return;

                }
                this.logCountTotal += apiResponse.PaginationDetails.CollectionSizeDelta.Value;
                this.pageIndex += (apiResponse.PaginationDetails.CollectionSizeDelta.Value / pageSize);
                if (apiResponse.PaginationDetails.SyncPointReference.HasValue)
                    this.syncPoint = apiResponse.PaginationDetails.SyncPointReference.Value;


                // If the user is looking at something (has changed the page), don't force a data refresh,
                // else load the new data into view
                if (this.pageIndex >= 1)
                    await InvokeAsync(StateHasChanged);
                else
                    await LoadData();

            }
        }
        catch
        {
            matToaster.Add(apiResponse.Message, MatToastType.Danger, "DB Log meta refresh failed");

        }
    }
    protected async Task LoadData()
    {
        ApiResponseDto apiResponse = null;
        try
        {
            apiResponse = await Http.GetFromJsonAsync<ApiResponseDto>($"api/DbLog?page={this.pageIndex}&pageSize={this.pageSize}");
            if (apiResponse.PaginationDetails.SyncPointReference.HasValue)
                this.syncPoint = apiResponse.PaginationDetails.SyncPointReference.Value;

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            throw;
        }

        if (apiResponse.StatusCode == Status200OK)
        {
            //matToaster.Add(apiResponse.Message, MatToastType.Success, "DB Log Items Retrieved");
            var nextPage = Newtonsoft.Json.JsonConvert.DeserializeObject<DbLog[]>(apiResponse.Result.ToString()).ToList<DbLog>();
            this.logCountTotal = apiResponse.PaginationDetails.CollectionSize ?? this.logCountTotal;
            this.dBLogItems = nextPage;

            //dBLogItems.AddRange(nextPage);
        }
        else if (apiResponse.StatusCode == Status204NoContent)
        {
            matToaster.Add(String.Empty, MatToastType.Info, "No more logs to fetch");

        }
        else
        {
            matToaster.Add(apiResponse.Message, MatToastType.Danger, "DB Log Items Retrieval Failed");
        }
        await InvokeAsync(StateHasChanged).ConfigureAwait(true);

    }



}
